package com.hjd.shop.serviceImpl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.hjd.shop.api.service.*;
import com.hjd.shop.base.Response;
import com.hjd.shop.constant.*;
import com.hjd.shop.entity.*;
import com.hjd.shop.exception.CastException;
import com.hjd.shop.mapper.SOrderMapper;
import com.hjd.shop.pojo.MqEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author 胡江迪
 * @since 2020-10-13
 */

@Component
@Service(interfaceClass = SOrderService.class)
@Slf4j
public class SOrderServiceImpl extends ServiceImpl<SOrderMapper, SOrder> implements SOrderService {
    @Reference
    private UserService userService;
    @Reference
    private SGoodsService goodsService;
    @Reference
    private SCouponService couponService;
    @Reference
    private GoodsNumberLogService goodsNumberLogService;
    @Reference
    private UserMoneyLogService userMoneyLogService;

    /**
     * 注入rocketmq
     */
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 读取properties中配置的mq的topic以及tag
     */
    @Value("${mq.order.tag.cancel}")
    private String topic;
    @Value("${mq.order.topic}")
    private String tag;

    @Override
    public Response confirmOrder(SOrder order) {
        //1.校验订单
        //2.生成预订单
        checkOrder(order);
        try {
            //3.扣减库存
            reduceGoodsNum(order);
            //4.扣减优惠券
            updateCouponStatus(order);
            //5.使用余额
            reduceMoneyPaid(order);
            //TODO 此处应抛出异常
            //6.确认订单
            order.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.name())
                    .setPayStatus(PayState.ORDER_PAYED.name())
                    .setConfirmTime(new Date())
                    .setModifyTime(new Date())
                    .setModifyUser(SystemUser.SYSTEM_USER);
            //7.返回成功状态
        }catch (Exception e) {
           //1.确认订单失败，封装并发送消息
            MqEntity mqEntity = new MqEntity();
            mqEntity.setGoodsId(order.getGoodsId())
                    .setCouponId(order.getCouponId())
                    .setGoodsNum(order.getGoodsNumber())
                    .setOrderId(order.getOrderId())
                    .setUserId(order.getUserId())
                    .setUserMoney(order.getMoneyPaid());
            //2.返回订单确认失败状态
            try {
                log.info("订单确认失败！开始向mq发送消息...");
                sendCancelOrder(topic,tag,order.getOrderId(),mqEntity.toString());
            } catch (Exception ex) {
                ex.printStackTrace();
            }finally {
                log.info("发送完毕！返回状态码...");
                return new Response(ShopCode.SHOP_FILED.getState(),ShopCode.SHOP_FILED.getMsg());
            }
        }
        return new Response(ShopCode.SHOP_SUCCESS.getState(),ShopCode.SHOP_SUCCESS.getMsg());
    }

    /**
     * 当订单确认失败，向mq发送消息
     * @param topic mq的topic
     * @param tag mq消息的tag
     * @param orderId mq消息的key
     * @param context 消息内容
     */
    private void sendCancelOrder(String topic, String tag, String orderId, String context) throws InterruptedException,
            RemotingException, MQClientException, MQBrokerException {
        Message message = new Message(topic,tag,orderId,context.getBytes());
        rocketMQTemplate.getProducer().send(message);
    }

    /**
     * 余额扣减
     * @param order
     */
    private void reduceMoneyPaid(SOrder order) {
        UserMoneyLog userMoneyLog = new UserMoneyLog();
        userMoneyLog.setOrderId(order.getOrderId())
                .setUserId(order.getUserId())
                .setUseMoney(order.getMoneyPaid())
                .setMoneyLogType(UserMoneyState.PAID_MONEY.getCode())
                .setCreateTime(new Date());
        userMoneyLogService.insert(userMoneyLog);
        userService.updateUserMoney(userMoneyLog);
        log.info("订单"+order.getOrderId()+"使用余额成功!");
    }

    /**
     * 更新优惠券
     * @param order
     */
    private void updateCouponStatus(SOrder order) {
        User user = userService.getUserById(order.getUserId());
        Condition condition = Condition.create();
        condition.eq("user_id",user.getId())
                .eq("coupon_id",order.getCouponId());
        SCoupon coupon = new SCoupon();
        coupon.setIsUsed(CouponState.IS_USED.getCode())
                .setUseTime(new Date())
                .setOrderId(order.getOrderId());
        couponService.update(coupon,condition);
        log.info("订单"+order.getOrderId()+"优惠券使用成功!");
    }

    /**
     * 扣减库存
     * @param order
     */
    private void reduceGoodsNum(SOrder order) {
        //更新商品库存信息
        SGoods goodsInfo = goodsService.getOneById(order.getGoodsId());
        //校验一下 库存是否充足 订单的商品数量是否大于库存
        if (goodsInfo.getGoodsNumber().compareTo(order.getGoodsNumber())==-1) {
            CastException.cast(ShopCode.GOODS_NUMBER_NOT_ENOUGH);
        }
        goodsInfo.setGoodsNumber(goodsInfo.getGoodsNumber()-order.getGoodsNumber());
        goodsService.updateById(goodsInfo);
        //将更新信息维护到日志表中
        GoodsNumberLog goodsNumberLog = new GoodsNumberLog();
        goodsNumberLog.setGoodsId(order.getGoodsId())
                .setOrderId(order.getOrderId())
                .setGoodsNumber(order.getGoodsNumber())
                .setCreateTime(new Date());
        goodsNumberLogService.insert(goodsNumberLog);
        log.info("订单"+order.getOrderId()+"扣减库存成功!");
    }

    /**
     * 校验订单
     * @param order
     * @return
     */
    private void checkOrder(SOrder order) {
        //1.订单是否存在
        if (null==order) {
            CastException.cast(ShopCode.SHOP_FILED);
        }
        //2.商品是否存在
        SGoods goods = goodsService.getOneById(order.getGoodsId());
        if (null==goods) {
            CastException.cast(ShopCode.GOODS_NOT_EXIST);
        }
        //3.下单用户是否存在
        if (null==userService.getUserById(order.getUserId())) {
            CastException.cast(ShopCode.GOODS_NOT_EXIST);
        }
        //4.订单金额是否合法
        if (order.getGoodsPrice().compareTo(goods.getGoodsPrice())!=0) {
            CastException.cast(ShopCode.ORDER_NOT_RIGHT);
        }
        //5.商品数量是否合法
        if (order.getGoodsNumber()>goods.getGoodsNumber()) {
            CastException.cast(ShopCode.GOODS_NUMS_NOT_RIGHT);
        }
        //生成预订单
        this.savePreOrder(order);
    }

    /**
     * 生成预订单
     * @param order
     * @return 订单ID
     */
    private String savePreOrder(SOrder order) {
        //1.设置订单不可见
        order.setOrderStatus(ShopCode.SHOP_ORDER_NOT_CONFIRM.name());
        //2.设置订单ID
        //3.核算订单运费
        BigDecimal shippingFee = this.calculateShippingFee(order.getOrderAmount());
        if (order.getShippingFee().compareTo(shippingFee)!=0) {
            CastException.cast(ShopCode.SHOP_FILED);
        }
        //4.核算订单总金额是否合法
        BigDecimal orderTotal = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));
        orderTotal.add(shippingFee);
        if (order.getOrderAmount().compareTo(orderTotal)!=0) {
            CastException.cast(ShopCode.SHOP_FILED);
        }
        //5.判断用户是否使用余额
        BigDecimal moneyPaid = order.getMoneyPaid();
        if (null!=moneyPaid) {
            //使用余额：需要去判断用户的余额 是否够用
            User userInfo = userService.getUserById(order.getUserId());
            if (userInfo.getUserMoney().compareTo(moneyPaid)==1) {
                //余额不足
                CastException.cast(ShopCode.USER_MONET_AMOUNT_NOT_ENOUGH);
            }
        }else {
            order.setMoneyPaid(BigDecimal.ZERO);
        }
        //6.判断用户是否使用优惠券
        SCoupon couponInfo = couponService.getOneById(order.getCouponId());
        if (null!=order.getCouponId()) {
            //判断优惠券是否存在

            if (null==couponInfo) {
                CastException.cast(ShopCode.COUPON_NOT_EXIST);
            }
            //判断优惠券是否已经使用
            if (!couponInfo.getIsUsed()) {
                CastException.cast(ShopCode.COUPON_IS_USED);
            }
        }else {
            order.setCouponPaid(couponInfo.getCouponPrice());
        }
        //7.核算订单支付信息 订单总金额-余额-优惠券
        order.setOrderAmount(orderTotal.subtract(moneyPaid).subtract(order.getCouponPaid()));
        //8.设置下单时间
        order.setAddTime(new Date());
        //9.保存订单到数据库
        baseMapper.insert(order);
        //10.返回订单ID
        return order.getId();
    }

    /**
     * 核算运费
     * @param orderPrice
     */
    private BigDecimal calculateShippingFee(BigDecimal orderPrice) {
        //商品总价格 大于100 不掏运费，反之10运费
        if (orderPrice.compareTo(new BigDecimal(100))==1) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(10);
    }
}
